#pragma semicolon 1
#include <sourcemod>
#include <cstrike>
#include <sdkhooks>
#include <sdktools>
#include <colors>
#include <PowerupsX>

#define MIN_ABILITY 1 

#define PREFIX "{olive}PowerupsX {default}>{green} "
#define abilityPickup "models/items/cs_gift.mdl"
#define Multiplier 50

new Handle:g_CvarEnable = INVALID_HANDLE;
new Handle:g_DropChance = INVALID_HANDLE;
new Handle:db = INVALID_HANDLE;

new bool:FirstSpawn[MAXPLAYERS + 1] = { true, ... };
new bool:CanPickup[MAXPLAYERS + 1] = { true, ... };
new AbilityKTNL[MAXPLAYERS + 1] = { 0, ... };

new ClientTempAbility[MAXPLAYERS + 1];
new ClientMenuLevel[MAXPLAYERS + 1];

new g_iHaloOrange;
new g_iHaloSprite;

new AbilityNone;

#include "PowerupsXDatabase.sp"
#include "PowerupsXInterface.sp"

public OnMapStart()
{
	g_iHaloOrange = PrecacheModel("materials/sprites/fire2.vmt");
	g_iHaloSprite = PrecacheModel("materials/sprites/halo01.vmt");
	PrecacheSound("buttons/button11.wav", true);
	PrecacheSound("buttons/blip2.wav", true);
	PrecacheSound("buttons/bell1.wav", true);
}

public Plugin:myinfo=
{
	name="PowerupsXL",
	author="Skydive",
	description="Powerups",
	version="1.0",
	url=""
};

public Action:OnGetGameDescription(String:gameDesc[64]) 
{ 
	strcopy(gameDesc, sizeof(gameDesc), "PowerupsX");
	return Plugin_Changed; 
}

public OnPluginStart()
{
	g_CvarEnable = CreateConVar("powerupX_enable", "1", "1 turns the plugin on 0 is off", FCVAR_NOTIFY);
	g_DropChance = CreateConVar("powerupX_dropchance", "27","Chance for drop +1 out of 100", FCVAR_NOTIFY);
	RegAdminCmd("sm_powerup", Command_Powerup, ADMFLAG_ROOT, "sm_powerup <#userid|name> [>0]");
	RegAdminCmd("sm_level", Command_Level, ADMFLAG_ROOT, "sm_level <#userid|name> [>0]");
	
	RegConsoleCmd("sm_info", Command_Info, "Opens The PowerupsX Help Menu");
	RegConsoleCmd("sm_reset", Command_Reset, "Resets Current Ability");
	
	AbilityNone = PX_RegisterAbilityNONE("AbilityNone");
	PX_SetAbilityName(AbilityNone,"None");
	PX_SetAbilityDescription(AbilityNone,"Just a regular Human.");
	PX_SetAbilityUsage(AbilityNone,"Make Kills And Get Powerups");
	PX_SetAbilityMaxLevel(AbilityNone,0);
	
	NativeIncStart();
	
	HookEvent("player_spawn",Event_PlayerSpawn);
	HookEvent("player_death",Event_PlayerDeath);
	
	HookEvent("round_mvp",Event_SpecialXPGain);
	HookEvent("bomb_defused",Event_SpecialXPGain);
	HookEvent("bomb_exploded",Event_SpecialXPGain);
	HookEvent("hostage_follows",Event_SpecialXPGain);
	HookEvent("hostage_rescued",Event_SpecialXPGain);
	HookEvent("round_end",Event_TeamSpecialXPGain);
	InitializeDB();
}

public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
{
   CreateNative("PX_SetAbility", Native_SetAbility);
   CreateNative("PX_GetAbility", Native_GetAbility);
   CreateNative("PX_SetLevel", Native_SetLevel);
   CreateNative("PX_GetLevel", Native_GetLevel);
   CreateNative("PX_RemoveAbilities", Native_RemoveAbilities);
   CreateNative("PX_SetPlayerColor", Native_SetPlayerColor);
   CreateNative("PX_SetAbilityColor", Native_SetAbilityColor);
   CreateNative("PX_AbilityUseColor", Native_AbilityUseColor);
   CreateNative("PX_SetAbilityMaxLevel", Native_SetAbilityMaxLevel);
   CreateNative("PX_GetAbilityMaxLevel", Native_GetAbilityMaxLevel);
   CreateNative("PX_RegisterAbility", Native_RegisterAbility);
   CreateNative("PX_RegisterAbilityNONE", Native_RegisterAbilityNONE);
   CreateNative("PX_GetRegisteredAbility", Native_GetRegisteredAbility);
   CreateNative("PX_GetRegisteredCodename", Native_GetRegisteredCodename);
   CreateNative("PX_RegisteredAbilitys", Native_RegisteredAbilitys);
   CreateNative("PX_SetAbilityName", Native_SetAbilityName);
   CreateNative("PX_GetAbilityName", Native_GetAbilityName);
   CreateNative("PX_SetAbilityDescription", Native_SetAbilityDescription);
   CreateNative("PX_GetAbilityDescription", Native_GetAbilityDescription);
   CreateNative("PX_SetAbilityUsage", Native_SetAbilityUsage);
   CreateNative("PX_GetAbilityUsage", Native_GetAbilityUsage);
   return APLRes_Success;
}

public Action:Event_PlayerSpawn(Handle:event, const String:name[],bool:dontBroadcast)
{
	new userid = GetClientOfUserId(GetEventInt(event,"userid"));
	if(FirstSpawn[userid] == true)
	{
		PX_SetAbility(userid,AbilityNone);
		FirstSpawn[userid] = false;
	}
	PX_SetPlayerColor(userid);
	CanPickup[userid] = true;
	if(PX_GetAbility(userid) != AbilityNone && IsFakeClient(userid))
	{
		UpdateData(userid);
	}
}

public Event_PlayerDeath(Handle:event,const String:name[],bool:dontBroadcast)
{
	new victim = GetClientOfUserId(GetEventInt(event,"userid"));
	new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
	
	if(GetConVarBool(g_CvarEnable))
	{
		if(victim == 0) { return; }
		if(attacker == 0) { return; }
		
		if(GetClientTeam(victim) != GetClientTeam(attacker)) // check first was attacker enemy. If not then check is mode "teamkill"
		{	
			
			AwardXP(attacker,1);
			
			new iActivePlayers = 0;
			//new i = Math_GetRandomInt(1,100);
			for(new i=1; i <= MaxClients; i++)
			{
				if(IsClientConnected(i) && IsClientInGame(i))
				{
					iActivePlayers++;
				}
			}
			
			new iRand = Math_GetRandomInt(1,100);
		
			new iChance = RoundToNearest(float(GetConVarInt(g_DropChance)-iActivePlayers));
			
			PrintToServer("Active: %d",iActivePlayers);
			PrintToServer("Random: %d",iRand);
			PrintToServer("Chance: %d",iChance);
			
			if(iRand < iChance)
			{
				decl Float:location[3];
				GetClientAbsOrigin(victim, location);
				TE_SetupBeamRingPoint(location, 10.0, 500.0, g_iHaloOrange, g_iHaloSprite, 0, 10, 0.6, 10.0, 0.5, { 0,255,255,255 }, 10, 0);
				TE_SendToAll();
				DoPickup(victim);
			}
		}
	}
}

DoPickup(client)
{
	new ent;
	
	if((ent = CreateEntityByName("prop_physics_multiplayer")) != -1)
	{
		new Float:pos[3], Float:vel[3], String:targetname[100];

		GetClientEyePosition(client, pos); // Let's try get position from higher

		// Random throw
		vel[0] = GetRandomFloat(-200.0, 200.0);
		vel[1] = GetRandomFloat(-200.0, 200.0);
		vel[2] = GetRandomFloat(100.0, 200.0);

		Format(targetname, sizeof(targetname), "abilitypickup_%i", ent);
		DispatchKeyValue(ent, "model", abilityPickup);
		DispatchKeyValue(ent, "physicsmode", "2"); 
		DispatchKeyValue(ent, "massScale", "1.0"); 
		DispatchKeyValue(ent, "targetname", targetname); 
		DispatchSpawn(ent); 

		TeleportEntity(ent, pos, NULL_VECTOR, vel);
		SetEntProp(ent, Prop_Send, "m_CollisionGroup", 1);
		
		SetEntProp(ent, Prop_Send, "m_usSolidFlags", 8);

		SDKHook(ent, SDKHook_TouchPost, StartPresentTouchPost);
	}
}

public StartPresentTouchPost(entity, activator, caller, UseType:type, Float:value)
{
	if(activator > 0 && activator <= MaxClients)
	{
		if(CanPickup[activator] == true)
		{
			new Float:fPlayerPos[3];
			GetClientEyePosition( activator, fPlayerPos );
			
			AcceptEntityInput(entity, "Kill");
			
			EmitAmbientSound( "buttons/bell1.wav", fPlayerPos, activator );
			if(IsFakeClient(activator))
			{
				PX_SetAbility(activator,GenerateAbilityRandom(activator));
			}
			else
			{
				new Ability = GenerateAbilityRandom(activator);
				GetSavedMenu(activator, Ability);
				OpenPickupPanel(activator, Ability);
			}
			
			CanPickup[activator] = false;
		}
	}
}

public OnClientDisconnect(Client)
{
	if (Client != 0)
	{
		PX_RemoveAbilities(Client);
	}
	if(PX_GetAbility(Client) != AbilityNone)
	{
		UpdateData(Client);
	}
}

public OnGameFrame()
{
	for(new client = 1; client <= MaxClients; client++)
	{
		if(!IsClientInGame(client)) continue;
		if(IsClientConnected(client))
		{
			if(IsPlayerAlive(client))
			{	
				DisplayClientHud(client,client, 0); // KeyHintText <3
				
				new Float:flBarStartTime = GetEntPropFloat(client, Prop_Send, "m_flProgressBarStartTime");
				new iBarDuration = GetEntProp(client, Prop_Send, "m_iProgressBarDuration");
				if(iBarDuration>0 && flBarStartTime+float(iBarDuration) < GetGameTime())
				{
					SetEntProp(client, Prop_Send, "m_iProgressBarDuration",0);
				}
			}
			else
			{
				new iSpecModeUser = GetEntProp(client, Prop_Send, "m_iObserverMode");
				new iTargetUser = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget");
				if (iSpecModeUser == 4 || iSpecModeUser == 5)
				{
					DisplayClientHud(client,iTargetUser, 1);
				}
				else
				{
					DisplayClientHud(client,iTargetUser, 2);
				}
			}
		}
	}
}

public OnClientSettingsChanged(Client)
{
	if (IsClientInGame(Client) && PX_GetAbility(Client) == AbilityNone)
	{
		CS_SetClientClanTag(Client, "None");
	}
}

public PXF_OnAbilityGiven(Client, Ability)
{

	decl String:sName[MAX_NAME_LENGTH];
	GetClientName(Client,sName,MAX_NAME_LENGTH);
		
	decl String:sAbility[32];
	PX_GetAbilityName(Ability,sAbility);
	
	PX_SetPlayerColor(Client);
	CS_SetClientClanTag(Client, sAbility);
	
	if(Ability == AbilityNone)
	{
		OnClientSettingsChanged(Client);
		return;
	}
	
	CPrintToChat(Client,"%s {green}You've Been Granted %s.", PREFIX, sAbility);
	CSkipNextClient(Client); CPrintToChatAll("%s{lightgreen}%s {green}Has Been Granted %s.", PREFIX, sName, sAbility);
	
	if(!IsFakeClient(Client))
	{
		LoadSavedData(Client);
	}
	else
	{
		PX_SetLevel(Client,Ability,1);
		AbilityKTNL[Client] = 0;
	}
}

public Event_SpecialXPGain(Handle:event, const String:name[], bool:dontBroadcast)
{
	new Client = GetClientOfUserId(GetEventInt(event,"userid"));
	new Ability = PX_GetAbility(Client);
	
	if(Ability != AbilityNone)
	{
		AwardXP(Client, Math_GetRandomInt(2,10));
	}
}
public Event_TeamSpecialXPGain(Handle:event, const String:name[], bool:dontBroadcast)
{
	new winner = GetEventInt(event, "winner");
	new Team = GetClientTeam(winner);
	for(new i = 1; i <= GetMaxClients(); i++)
	{
		if(IsClientInGame(i))
		{
			if(PX_GetAbility(i) != AbilityNone && GetClientTeam(i) == Team)
			{
				AwardXP(winner, Math_GetRandomInt(1,3));
			}
		}
	}
}

public PXF_OnAbilityRemoved(Client, Ability)
{
	if(Ability != AbilityNone && !IsFakeClient(Client))
	{
		UpdateData(Client);
	}
}

public DisplayClientHud(Client, PickedClient, mode)
{
	decl String:sAbility[32];
	decl String:fText[128];
	
	if(mode == 2)
	{
		Format(fText,sizeof(fText),"Powerups XL\nSpectating: Free Look");
		KeyHintText(Client, fText);
		return;
	}
	

	if(PX_GetAbility(PickedClient) == AbilityNone)
	{
		FormatEx(fText,sizeof(fText),"Powerups XL\n__________\nName: None\nPick up a present for an ability!\n__________\n");
		KeyHintText(Client, fText);
	}
	else
	{
		PX_GetAbilityName(PX_GetAbility(PickedClient),sAbility);
	
		new Level = PX_GetLevel(PickedClient,PX_GetAbility(PickedClient));
		new MaxLevel = PX_GetAbilityMaxLevel(PX_GetAbility(PickedClient));
	
		if(mode == 0)
		{
			if(Level >= MaxLevel)
			{
				Format(fText,sizeof(fText),"Powerups XL\n__________\nName: %s\nLevel: %d/%d\n__________\n",sAbility, Level, MaxLevel, AbilityKTNL[PickedClient], (Level+1)*Multiplier);
			}
			else
			{
				Format(fText,sizeof(fText),"Powerups XL\n__________\nName: %s\nLevel: %d/%d\nXP: %d/%d\n__________\n",sAbility, Level, MaxLevel, AbilityKTNL[PickedClient], (Level+1)*Multiplier);
			}
		}
		if(mode == 1)
		{
			decl String:sName[MAX_NAME_LENGTH];
			GetClientName(PickedClient,sName,MAX_NAME_LENGTH);
					
			if(Level >= MaxLevel)
			{
				Format(fText,sizeof(fText),"Powerups XL\nSpectating: %s\n__________\nName: %s\nLevel: %d/%d\n__________\n", sName, sAbility, Level, MaxLevel, AbilityKTNL[PickedClient], (Level+1)*Multiplier);
			}
			else
			{
				Format(fText,sizeof(fText),"Powerups XL\nSpectating: %s\n__________\nName: %s\nLevel: %d/%d\nXP: %d/%d\n__________\n",  sName, sAbility, Level, MaxLevel, AbilityKTNL[PickedClient], (Level+1)*Multiplier);
			}
		}
		KeyHintText(Client, fText);
	}
}

public Action:Command_Powerup(client, args)
{
	if (args < 2)	{ ReplyToCommand(client, "[SM] Usage: sm_powerup <#userid|name> <AbilityRegister>");	return Plugin_Handled;	}
	decl String:arg[65], String:strnum[64];
	GetCmdArg(1, arg, sizeof(arg));
	GetCmdArg(2, strnum, sizeof(strnum));
	decl String:target_name[MAX_TARGET_LENGTH];
	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
	if ((target_count = ProcessTargetString(
			arg,
			client,
			target_list,
			MAXPLAYERS,
			COMMAND_FILTER_CONNECTED,
			target_name,
			sizeof(target_name),
			tn_is_ml)) <= 0)
	{
		ReplyToTargetError(client, target_count);
		return Plugin_Handled;
	}
	for (new i = 0; i < target_count; i++)
	{
		if(IsCharNumeric(strnum[0]))
		{
			new Ability = StringToInt(strnum);
			PX_SetAbility(target_list[i], Ability);
		}
		else
		{
			new Ability = PX_GetRegisteredAbility(strnum);
			if(Ability >= 0 && Ability <= PX_RegisteredAbilitys())
			{
				PX_SetAbility(target_list[i], Ability);
			}
			else
			{
				PrintToChat(target_list[i],"Invalid Ability!");
			}
		}
	}
	return Plugin_Handled;
}

public Action:Command_Level(client, args)
{
	if (args < 2)	{ ReplyToCommand(client, "[SM] Usage: sm_level <#userid|name> [value]");	return Plugin_Handled;	}
	decl String:arg[65], String:strnum[10];
	GetCmdArg(1, arg, sizeof(arg));
	GetCmdArg(2, strnum, sizeof(strnum));
	new num = StringToInt(strnum);
	decl String:target_name[MAX_TARGET_LENGTH];
	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
	if ((target_count = ProcessTargetString(
			arg,
			client,
			target_list,
			MAXPLAYERS,
			COMMAND_FILTER_CONNECTED,
			target_name,
			sizeof(target_name),
			tn_is_ml)) <= 0)
	{
		ReplyToTargetError(client, target_count);
		return Plugin_Handled;
	}
	for (new i = 0; i < target_count; i++)
	{
		AwardXP(target_list[i],num);
	}

	return Plugin_Handled;
}



public OnAllPluginsLoaded()
{
	if (GetExtensionFileStatus("sdkhooks.ext") != 1)
	{
		SetFailState("SDKHooks not found");
	}
}

public OnLibraryRemoved(const String:name[])
{
	if (strcmp(name, "sdkhooks.ext") == 0)
	{
		SetFailState("SDKHooks not found");
	}
}

stock GenerateAbilityRandom(Client)
{
	new Abilitys = PX_RegisteredAbilitys();
	new foo = Math_GetRandomInt(MIN_ABILITY,Abilitys-1);
	new bar = PX_GetAbility(Client);
	while(foo == bar)
	{
		foo = Math_GetRandomInt(MIN_ABILITY,Abilitys-1);
	}
	return foo;
}

stock AwardXP(Client,amount)
{
	if(!IsFakeClient(Client))
	{
		new Ability = PX_GetAbility(Client);
		if(Ability != AbilityNone)
		{
			new Level = PX_GetLevel(Client, Ability);
			new MaxLevel = PX_GetAbilityMaxLevel(Ability);
				
			if(Level < MaxLevel)
			{
				AbilityKTNL[Client] += amount;
				if(AbilityKTNL[Client] >= (Level+1)*Multiplier)
				{
					PX_SetLevel(Client, Ability, Level+1);
					AbilityKTNL[Client] = 0;
					
					decl String:sName[MAX_NAME_LENGTH];
					decl String:sAbility[32];
					
					GetClientName(Client,sName,MAX_NAME_LENGTH);
					PX_GetAbilityName(Ability,sAbility);
					
					CPrintToChat(Client,"%s {green}You are now Level: %d On %s.", PREFIX, Level+1, sAbility);
					CSkipNextClient(Client); CPrintToChatAll("%s{lightgreen}%s {green}Is now Level: %d On %s.", PREFIX, sName, Level+1, sAbility);
				}
			}
			UpdateData(Client);
		}
	}
}